package com.ntty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * 搭建整体处理框架 （带主子线程） 规定了一个服务只处理一种模型，模型大小不限
 */
public class NettyServer {
	/*
	 * 服务端由两种线程池， 用于Acceptor的React主线程(bossGroup)和用于I/O操作的React从线程池(workerGroup)；
	 * 客户端只有用于连接及IO操作的React的主线程池；
	 */
	private EventLoopGroup bossGroup;
	private EventLoopGroup workerGroup;
	private int port;
	private String host;
	private ChannelHandler _model;

	private NettyServer(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public static NettyServer getInstance(int port) {
		return new NettyServer("localhost", port);
	}

	public static NettyServer getInstance(String host, int port) {
		return new NettyServer(host, port);
	}

	public NettyServer addInitializer(ChannelHandler control) {

		_model = control;
		return this;
	}

	/** 规定了一个服务只处理一种模型 */
	@SuppressWarnings("finally")
	public boolean start() {
		if (_model == null)
			return false;
		if (bossGroup == null)
			/*
			 * 2.创建两个线程池 第一个 监听端口号 nio监听 EventLoopGroup继承与ScheduledExecutorService， 有定时执行的味道
			 * 其中boss用来监控 端口请求,worker用来处理io事件. 具体的说： boss执行 server.accept()操作
			 * worker处理事件的读写到业务逻辑处理等后续操作.
			 */
			bossGroup = new NioEventLoopGroup(1);
		if (workerGroup == null)
			workerGroup = new NioEventLoopGroup();

		try {
			// 1.创建服务对象
			// 使用ServerBootstrap类来初始化netty服务器，并且开始监听端口的socket请求
			ServerBootstrap bootstrap = new ServerBootstrap();

			// 2.绑定专用线程池
			bootstrap.group(bossGroup, workerGroup);

			/*
			 * 4.1 修改配置 Option是为了NioServerSocketChannel设置的，用来接收传入连接的
			 */
		
			bootstrap.option(ChannelOption.SO_SNDBUF, 1048576*200);
		    bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
			bootstrap.option(ChannelOption.SO_BACKLOG, 1024); // 连接数，用于临时存放已完成三次握手的请求的队列的最大长度
			bootstrap.option(ChannelOption.TCP_NODELAY, true); // 不延迟，消息立即发送
			bootstrap.channel(NioServerSocketChannel.class);
			/*
			 * 5. 实现worker线程处理的接口 child=》worker
			 * 
			 * option / handler / attr方法都定义在AbstractBootstrap中，
			 * 
			 * 所以服务端和客户端的引导类方法调用都是调用的父类的对应方法。
			 * 
			 * option： 设置通道的选项参数， 对于服务端而言就是ServerSocketChannel， 客户端而言就是SocketChannel；
			 * 
			 * handler： 设置主通道的处理器， 对于服务端而言就是ServerSocketChannel，也就是用来处理Acceptor的操作；
			 * 
			 * handler： 对于客户端的SocketChannel，主要是用来处理 业务操作；
			 * 
			 * attr： 设置通道的属性；
			 * 
			 * childHandler / childOption / childAttr 方法（只有服务端ServerBootstrap才有child类型的方法）
			 * 
			 * 对于服务端而言，有两种通道需要处理， 一种是ServerSocketChannel：用于处理用户连接的accept操作，
			 * 另一种是SocketChannel，表示对应客户端连接。
			 * 
			 * 而对于客户端，一般都只有一种channel，也就是SocketChannel。
			 * 
			 * handler在初始化时就会执行，而childHandler会在客户端成功connect后才执行，这是两者的区别。
			 */
			// if (control==null)
			// control=new HelloWorldHandler();
			// bootstrap.childHandler(control);

			bootstrap.childHandler(_model);
			// 6.配置好服务器，在服务器启动时绑定闯入的port端口，等待同步
			ChannelFuture channelFuture = null;
			if (host == null)
				channelFuture = bootstrap.bind(port).sync();
			else
				channelFuture = bootstrap.bind(host, port).sync();
			System.out.println("服务已启动。。。");
			// 7.如果绑定成功 发起异步连接操作
			/*
			 * channelFuture.addListener(new ChannelFutureListener() {
			 * 
			 * @Override public void operationComplete(ChannelFuture future) { if
			 * (future.isSuccess()) {
			 * 
			 * } else { // 输出错误信息 Throwable cause = future.cause(); cause.printStackTrace();
			 * // do something.... } } });
			 */
			// 8.等待服务端监听端口关闭
			channelFuture.channel().closeFuture().sync();
		
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			// 优雅释放
			bossGroup.shutdownGracefully();
			workerGroup.shutdownGracefully();
			return true;
		}
	}

}
